/**
 * @file spi_test_cmd.c
 * @author Rocky
 * @brief 单片机到FPGA的SPI测试，读出地址0寄存器: FPGA Chip ID，读出值为0xabcd即代表通讯成功
 * @version 0.1
 * @date 2024-03-22
 *
 * @copyright Copyright (c) 2024
 *
 */

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <fcntl.h>
#include <time.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#include <sys/stat.h>

#include "spidev_interface.h"

#define PROGRAM_NAME "spi_test_cmd"

static int fpga_spi_fd;
static uint32_t fpga_spi_mode = 0;
static int8_t fpga_spi_bits = 8;
static uint32_t fpga_spi_speed = 500000;

static void spi_write_fpga(uint16_t page, size_t offset, uint16_t val)
{
    uint8_t tx[4];
    uint8_t rx[4];
    uint16_t addr;

    /* 读写接口参考 HB YSYZ FPGA 用户手册v1.5 */
    if (page > 3 || offset > 256)
        errmsg_die("invalid page or invalid offset");

    addr = 0x100 * page + offset;

    tx[0] = 0x2c; // 00 1011 00，1011代表读操作
    tx[0] |= (addr >> 8) & 0xff;
    tx[1] = addr & 0xff;
    tx[2] = (val >> 8) & 0xff;
    tx[3] = val & 0xff;

    transfer(fpga_spi_fd, tx, rx, 4);
}

/**
 * @brief 从FPGA指定地址读出16位宽的数据
 *
 * @param page 页号
 * @param offset 偏移量
 * @return uint16_t
 */
static uint16_t spi_read_fpga(uint16_t page, size_t offset)
{
    uint8_t tx[5];
    uint8_t rx[5];
    uint16_t addr, result;

    /* 读写接口参考 HB YSYZ FPGA 用户手册v1.5 */
    if (page > 3 || offset > 256)
        errmsg_die("invalid page or invalid offset");

    addr = 0x100 * page + offset;
    tx[0] = 0x28; // 00 1010 00，1010代表读操作
    tx[0] |= (addr >> 8) & 0xff;
    tx[1] = addr & 0xff;
    tx[2] = 0;
    tx[3] = 0;
    transfer(fpga_spi_fd, tx, rx, 5);

    rx[2] = rx[2] << 2;
    rx[2] = (rx[3] >> 6) & 0xff | rx[2];
    rx[3] = rx[3] << 2;
    rx[3] = (rx[4] >> 6) & 0xff | rx[3];

    result = (rx[2] << 8) | rx[3];
    return result;
}

int main(int argc, char *argv[])
{
    int ret;

    // 与FPGA通讯的SPI设备是：/dev/spidev2.0
    fpga_spi_fd = init_spi("/dev/spidev2.0");
    set_spi_mode(fpga_spi_fd, fpga_spi_mode, fpga_spi_bits, fpga_spi_speed);

    // 读Page 0， Addr 0的寄存器的值
    printf("FPGA REG0 = %x\n", spi_read_fpga(0, 0));
    printf("FPGA REG4 = %x\n\n", spi_read_fpga(0, 4));

    uint16_t val = 0x5678;
    spi_write_fpga(0, 4, val);
    printf("Write %x to FPGA REG4\n", val);
    printf("FPGA REG4 = %x\n", spi_read_fpga(0, 4));

    printf("\nRAM: \n");
    for (int i = 0; i < 256; i++)
    {
        printf("%04x ", spi_read_fpga(3, i));
        if ((i + 1) % 16 == 0)
            printf("\n");
    }
    close_spi(fpga_spi_fd);

    return ret;
}
